package com.hfzy.ihk.web.linkcall.biz.KnowledgeBase;

import com.alibaba.fastjson.JSON;
import com.hfzy.ihk.common.constants.GlobalStatic;
import com.hfzy.ihk.common.core.elasticsearch.ElasticsearchOperation;
import com.hfzy.ihk.common.core.elasticsearch.EsQueryUtils;
import com.hfzy.ihk.common.core.elasticsearch.anotations.BestDoSupport;
import com.hfzy.ihk.common.core.elasticsearch.base.BestDoContextHolder;
import com.hfzy.ihk.common.core.elasticsearch.service.EsBaseServiceImpl;
import com.hfzy.ihk.common.util.string.StringUtil;
import com.hfzy.ihk.common.web.WebResult;
import com.hfzy.ihk.facade.linkcall.entity.knowledge.KnowledgeBase;
import com.hfzy.ihk.facade.linkcall.entity.knowledge.QuestionBase;
import com.hfzy.ihk.facade.linkcall.enums.KnowledgeBase.QuestionBaseOperations;
import com.hfzy.ihk.facade.linkcall.enums.KnowledgeBase.QuestionBaseTables;
import com.hfzy.ihk.facade.linkcall.enums.QuestionStatus;
import com.hfzy.ihk.facade.linkcall.vo.knowledgeBase.KnowledgeBaseVo;
import com.hfzy.ihk.web.linkcall.dao.QuestionBaseRepository;
import com.hfzy.ihk.web.linkcall.support.annotation.PreProcessParam;
import com.hfzy.ihk.web.linkcall.utils.LayUiParamUtils;
import com.hfzy.ihk.web.linkcall.utils.UserUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Auther: ouyicong
 * @Date: 2018/8/14 01:28
 * @Description: 操作学习分析的Biz(业务逻辑)
 */
@Service
public class QuestionBaseBiz extends EsBaseServiceImpl<QuestionBase> {

    Logger logger = LoggerFactory.getLogger(QuestionBaseBiz.class);

    @Autowired
    private ElasticsearchTemplate  elasticsearchTemplate;

    @Autowired
    private QuestionBaseRepository questionBaseRepository;

    @Autowired
    private KnowledgeBaseBiz knowledgeBaseBiz;

    @Override
    protected ElasticsearchCrudRepository getReposity() {

        return questionBaseRepository;
    }




    /**
     * 功能描述:新增问题并且开始维护版本
     *
     * @param: [questionBase]
     * @return: boolean
     * @auther:
     * @date: 2018/8/14
     */
   /* public boolean esInsert(QuestionBase questionBase) {

        //先判断在进行保存
        if (questionBase != null && questionBase.getId() != null) {

            //保存数据并且开始维护版本
            boolean flag = createDataAndSetVersion(QuestionBaseRedisVersionKey.TABLE_QUESTIONBASE,
                    QuestionBaseTables.QUESTIONBASE, questionBase.getId(),
                    questionBase.getVersion(), () -> insert(questionBase));

            return flag;
        }

        return false;
    }*/


    /**
     * 功能描述: 分页查询
     *
     * @param: [
     * key : 查询关键字
     * page :当前页
     * limit:每页大小
     * ]
     * @return: 用于封装layui所需的结果
     * @auther:
     * @date: 2018/8/7
     */
    @PreProcessParam
    public Map<String, Object> queryQuestionBaseBySearch(Map<String,Object> keymap, Integer page, Integer limit) {


        try {

            //用于拼接封装查询条件
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

            if (keymap.size()>0) {//当用户输入关键字

                if (keymap.containsKey("question")){

                    String question=(String)keymap.get("question");

                    if (StringUtil.isNotNull(question)){

                        //模糊查询
                        boolQuery.must(QueryBuilders.wildcardQuery("question", "*"+question+"*"));
                    }

                }

                if(keymap.containsKey("status")){

                    QuestionStatus status=(QuestionStatus)keymap.get("status");

                    boolQuery.must(QueryBuilders.termQuery("status",status.toString()));
                }

                if(keymap.containsKey("packageId")){
                    boolQuery.must(QueryBuilders.termQuery("packageId",keymap.get("packageId")));
                }
                if(keymap.containsKey("createUserId")){
                    boolQuery.must(QueryBuilders.termQuery("createUserId",keymap.get("createUserId")));
                }
            }                           //用户没输入关键字

            boolQuery.must(EsQueryUtils.matchAllQuerty());//查询所有的问题

            //按学习状态status状态进行排序
            SortBuilder statusSortBuilder = SortBuilders.fieldSort("status").order(SortOrder.DESC);
            //按更新时间进行排序
            SortBuilder modTimeBuilder = SortBuilders.fieldSort("modTime").order(SortOrder.DESC);


            NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withQuery(boolQuery)
                    .withSort(statusSortBuilder)
                    .withSort(modTimeBuilder)
                    //用于分页
                    .withPageable(PageRequest.of(page - 1, limit)).build();

            Page<QuestionBase> pageSearch = questionBaseRepository.search(searchQuery);

            //工具类封装layui表格所需参数
            Map<String, Object> resultMap = LayUiParamUtils.getInstance().toLayuiTableMap(pageSearch);

            return resultMap;

        } catch (Exception e) {

            //用于储存需要返回layui的结果集
            Map<String, Object> errorMap = new HashMap<>();

            logger.error("查询列表错误", e);
            errorMap.put("code", "1");//状态码,0代表成功.切记
            errorMap.put("msg", "目前访问人数过多,请亲稍后重试");
            errorMap.put("count", null);
            errorMap.put("data", null);
            return errorMap;
        }

    }

    /**
     * 功能描述:根据ID删除单个用户
     *
     * @param: [id : 需要删除的对象ID]
     * @return: boolean :删除是否成功
     * @auther:
     * @date: 2018/8/6
     */
    public WebResult esDeleteById(String id) {

        //封装结果集
        WebResult result = new WebResult();

        try {
            if (StringUtil.isNotNull(id)) {

                deleteById(id);

                result.setMsg("删除成功!");
                result.setParameter(id);
                result.setCode(GlobalStatic.CODE_1);
                return result;
            }

            result.setMsg("删除ID不能为空");
            result.setCode(GlobalStatic.CODE_0);

            return result;
        } catch (Exception e) {

            logger.error("删除异常", e);

            result.setMsg("服务器正忙,请稍后重试");
            result.setCode(GlobalStatic.CODE_0);
            return result;
        }

    }


    /**
     * 功能描述: 学习问题(就是新增一条知识库里KnowledgeBase,
     * 再修改下这边QuestionBase的状态)
     *
     * @return: com.hfzy.ihk.common.web.WebResult
     * @auther:
     * @date: 2018/8/14
     */
    @BestDoSupport(needReturnSuccess = true)//默认是返回状态码为1(即成功才进行次要操作)
    public WebResult insertOrUpdate(KnowledgeBaseVo knowledgeBaseVo, String qid) {

        WebResult result = new WebResult();

        try { //查询出需要修改状态的QuestionBase
            QuestionBase questionBase = selectById(qid);

            //假如查询此问题
            if (questionBase != null) {

                //获取事务ID
                String txId = BestDoContextHolder.getTransactionId();

                if (txId != null) {
                    //新增一条待执行的操作,添加到线程变量
                    ElasticsearchOperation operation = new ElasticsearchOperation
                            (txId, QuestionBaseTables.QUESTIONBASE.getTableName(),
                                    QuestionBaseOperations.updateQuestionBase.getOperationName(),
                                    questionBase);
                    BestDoContextHolder.addOperation(operation);
                }
            }

            boolean flag;

            if (knowledgeBaseVo.getId() != null && knowledgeBaseVo.getId() != "") {

                flag = knowledgeBaseBiz.esUpdateSomeFiled(knowledgeBaseVo);

                result.setMsg("学习问题成功,知识库已修改一条问题!");

            } else {

                logger.info("新增知识库:"+ JSON.toJSONString(knowledgeBaseVo));

                KnowledgeBase knowledgeBase = new KnowledgeBase();
                //将Vo属性封装到实体类
                knowledgeBaseBiz.setVoToEntity(knowledgeBaseVo, knowledgeBase);
                knowledgeBase.setCreateUserId(UserUtils.getCurrentUserId()!=null?UserUtils.getCurrentUserId():0l);
                //在此之前执行保存前,保证前面页面逻辑不出错
                 knowledgeBaseBiz.insert(knowledgeBase);
                result.setMsg("学习问题成功,知识库已新增一条问题!");
            }

            result.setCode(GlobalStatic.CODE_1);
/*            if (!flag) {
                logger.error("保存知识库KnowledgeBase异常");
                result.setMsg("服务器正忙,请稍后重试");
                result.setCode(GlobalStatic.CODE_0);

            }*/

            return result;

        } catch (Exception e) {

            logger.error("保存知识库KnowledgeBase异常", e);
            result.setMsg("服务器正忙,请稍后重试");
            if (e.getMessage().equals("此标题刚刚已经被使用了")){
                result.setMsg("此标题刚刚已经被使用了");
            };
            result.setCode(GlobalStatic.CODE_0);

            return result;
        }
    }


    /**
     * es
     *
     * @param
     * @return
     */
    public boolean esUpdateByFiled(long currentDataVersion, String dataId,
                                   Class entityClass,
                                   Map<String, Object> fieldValueMap) {

       /* boolean flag = checkVersionAndUpdateData(QuestionBaseRedisVersionKey.TABLE_QUESTIONBASE,
                QuestionBaseTables.QUESTIONBASE,
                dataId,
                currentDataVersion,
                () -> questionBaseRepository.updateSomeFields(dataId, entityClass, fieldValueMap));*/
        questionBaseRepository.updateSomeFields(dataId, entityClass, fieldValueMap);

        return true;
    }

    /**
     * 更新状态,改为已学习
     * @return
     */
    public boolean esUpdateByFiledForStatus(QuestionBase questionBase){

        //版本号加一
        long updateVersion = questionBase.getVersion() + 1L;

        Map<String,Object> map=new HashMap<>();

        map.put("status", QuestionStatus.HAS_LEARN);

        map.put("modTime",new Date());

        map.put("version",updateVersion);

        boolean flag = esUpdateByFiled(questionBase.getVersion(), questionBase.getId(), QuestionBase.class, map);

        return flag;

    }


    /**
     *
     * 功能描述:添加未识别问题
     *
     * @param: [questionBase]
     * @return: boolean
     * @auther:
     * @date: 2018/8/28
     */
    @Override
    public boolean insert(QuestionBase questionBase){

        try {

            getReposity().save(questionBase);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("保存出错",e);
            return false;
        }

        return true;
    }

    @PreProcessParam
    public Page<QuestionBase> getQuestionBaseByPage(Map<String,String> params){
        BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(params);
        int pageNum = Integer.valueOf(params.get("page"))-1;
        int pageSize = Integer.valueOf(params.get("pageSize"));
        //添加排序字段
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withSort(fieldSortBuilder).withPageable(PageRequest.of(pageNum,pageSize));
        return questionBaseRepository.search(builder.build());
    }


    public BoolQueryBuilder getQueryBuilderByParams(Map<String,String> params){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Iterator entries = params.entrySet().iterator();
        while (entries.hasNext()){
            Map.Entry entry = (Map.Entry) entries.next();
            String key = entry.getKey().toString();
            switch (key){
                case "createTimeStart":
                    boolQueryBuilder.must(EsQueryUtils.rangeQuery("createTime", params.get("createTimeStart"),
                            null, true, false));
                    break;
                case "createTimeEnd" :
                    boolQueryBuilder.must(EsQueryUtils.rangeQuery("createTime", null,
                            params.get("createTimeEnd"), false, true));
                    break;
                case "status":
                    QueryBuilder status = EsQueryUtils.wildcardQuery("status", params.get("status"));
                    EsQueryUtils.boolQuery(boolQueryBuilder, EsQueryUtils.BoolType.MUST, status);
                    break;
                case "modUserId":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("modUserId.keyword",params.get("modUserId")));
                    break;
                default:
                    break;
            }
        }
        return boolQueryBuilder;
    }

    /**
     *根据上传的参数参数Questionbase
     * @param params
     * @return
     */
    public List<QuestionBase> searchByParam(Map<String,Object> params){
        List<QuestionBase> resultList=new ArrayList<>();
        try {

            //如果没有参数直接查全部
            if (params==null||params.keySet().size()==0){
                //List<QuestionBase> resultList=new ArrayList<>();
                resultList = selectAll();
            }else {
                //如果有参数,遍历map拼接查询条件
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

                //初始页
                int page=0;

                //默认大小
                int size=30;

                Iterator<String> iterator = params.keySet().iterator();

                while (iterator.hasNext()){

                    String key=iterator.next();

                    switch (key){
                        case "createUserId":
                            boolQueryBuilder.must(QueryBuilders.termQuery("createUserId",params.get(key)));
                            break;
                        case "status":
                            boolQueryBuilder.must(QueryBuilders.termQuery("status",params.get(key)));
                            break;
                        case "page":
                            page=Integer.parseInt((String) params.get(key));
                            break;
                        case "size":
                            size=Integer.parseInt((String) params.get(key));
                            break;

                    }

                }

                PageRequest of = PageRequest.of(page, size);

                List<QuestionBase> searchList=new ArrayList<>();

                List<QuestionBase> content = questionBaseRepository.search(boolQueryBuilder, of).getContent();

                if (content!=null&&!content.isEmpty()){

                    content.forEach(questionBase -> {
                        searchList.add(questionBase);
                    });

                }
                resultList=searchList;
            }
            //进行排序,暂时先这样做,迟点找到es既可以查全部又可以排序的再改
            resultList.sort((o1, o2) -> {
                long o1Time = o1.getCreateTime().getTime();
                long o2Time = o2.getCreateTime().getTime();
                if (o1Time>o2Time){
                    return -1;
                }else if (o1Time<o2Time){
                    return 1;
                }
                return 0;
            });
        }catch (Exception e){
            e.printStackTrace();
            logger.error("查询未识别问题出错");
            resultList.clear();
            return  resultList;
        }

        return  resultList;
    };
   /* public List<QuestionBase> searchByParam(Map<String,Object> params){
        List<QuestionBase> resultList=new ArrayList<>();
        try {

            //如果没有参数直接查全部
            if (params==null||params.keySet().size()==0){
                //List<QuestionBase> resultList=new ArrayList<>();
                 resultList = selectAll();
            }else {
                //如果有参数,遍历map拼接查询条件
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

                params.forEach((s, o) -> {

                    switch (s){

                        case "status":
                            boolQueryBuilder.must(QueryBuilders.termQuery("status",o));
                        break;

                    }

                });
                List<QuestionBase> searchList=new ArrayList<>();
                questionBaseRepository.search(boolQueryBuilder).forEach(questionBase -> {
                    searchList.add(questionBase);
                });

                resultList=searchList;
            }
            //进行排序,暂时先这样做,迟点找到es既可以查全部又可以排序的再改
            resultList.sort((o1, o2) -> {
                long o1Time = o1.getCreateTime().getTime();
                long o2Time = o2.getCreateTime().getTime();
                if (o1Time>o2Time){
                    return -1;
                }else if (o1Time<o2Time){
                    return 1;
                }
                return 0;
            });
        }catch (Exception e){
            e.printStackTrace();
            logger.error("查询未识别问题出错");
            resultList.clear();
            return  resultList;
        }

        return  resultList;
    };*/
}
